package com.hdax.dm.service.Impl;

import cn.hutool.Hutool;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hdax.dm.service.queryorderlistService;
import com.hdax.dm.utils.request.tokenutil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hdax.dm.beans.Scheduler.DmSchedulerSeat;
import com.hdax.dm.beans.Scheduler.DmSchedulerSeatPrice;
import com.hdax.dm.beans.item.Item;
import com.hdax.dm.beans.order.order;
import com.hdax.dm.beans.order.orderLinkUser;
import com.hdax.dm.beans.user.LinkUser;
import com.hdax.dm.constant.ErrConstant;
import com.hdax.dm.feign.itemFeign;
import com.hdax.dm.feign.schedulerFeign;
import com.hdax.dm.feign.userFeign;
import com.hdax.dm.mappers.orderLinkUserMapper;
import com.hdax.dm.service.submitorderService;
import com.hdax.dm.utils.request.tokenutil;
import com.hdax.dm.utils.response.CommonResponse;
import com.hdax.dm.utils.response.ResponseUtil;
import com.hdax.dm.vo.submitorderVo;
import io.jsonwebtoken.Claims;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class submitorderServiceImpl extends ServiceImpl<orderLinkUserMapper, orderLinkUser> implements submitorderService {

    @Autowired
    private itemFeign itemFeign;

    @Autowired
    private schedulerFeign schedulerFeign;

    @Autowired
    private userFeign userFeign;

    @Autowired
    private queryorderlistService queryorderlistService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public CommonResponse<Map<String,String>> submitorder(submitorderVo vo, HttpServletRequest request) {
        //锁定剧院
        // setIfAbsent:相当于redis中的setnx参数类型，如果存在当期键则加锁失败，不存在则加锁成功 四个参数 第一个第二个分别为键值，第三个是自动解锁时间，第四个是时间单位
        Boolean islock = redisTemplate.opsForValue().setIfAbsent("lock","yes",500, TimeUnit.MILLISECONDS);

        //自定义一个死循环，当上一个用户解锁后即可退出死循环
        while (!islock){
            islock = redisTemplate.opsForValue().setIfAbsent("lock","yes",500, TimeUnit.MILLISECONDS);
        }

        //获取token解密获得userId
        Claims claims = tokenutil.parserToken(request.getHeader("token"));
        String userId=claims.getId();
        //订单总金额
        Double price = 0D;
        //排期ID
        Integer schedulerId=vo.getSchedulerId().intValue();

        //声明变量
        order order = new order();

        //1.生成订单编号 雪花算法
        Snowflake snowflake = IdUtil.getSnowflake(1,1);
        String id = snowflake.nextIdStr();

        //查询ItemId对应的商品信息
        Long itemId = vo.getItemId();
        Item item = itemFeign.item(itemId.intValue());

        //解析座位 x1_y1,x2_y2
        String[] seats = vo.getSeatPositions().split(",");

        //解析联系人 id1,id2
        String[] linkuserId = new String[seats.length];


        if (seats.length != linkuserId.length) {
            //保证人票一致，不一致则返回错误信息
            return ResponseUtil.returnFail(ErrConstant.ErrCodeConstant.TICKET_CODE_INCONSISTENCY,ErrConstant.ErrMsgConstant.TICKET_MSG_INCONSISTENCY);
        }

        for (int i = 0; i < seats.length; i++) {
            Long x = Long.parseLong(seats[i].split("_")[0]);
            Long y = Long.parseLong(seats[i].split("_")[1]);

            //根据条件查询数据库保证该座位是可以被购买的
            DmSchedulerSeat dmSchedulerSeat = schedulerFeign.dm(x,y,schedulerId);
            if (dmSchedulerSeat==null) {
                return ResponseUtil.returnFail(ErrConstant.ErrCodeConstant.SEAT_CODE_OCCUPATION,ErrConstant.ErrMsgConstant.SEAT_MSG_OCCUPATION);
            }
            //根据排期id和座位等级查询出该座位的价格
            DmSchedulerSeatPrice dmprice = schedulerFeign.dmprice(schedulerId.longValue(),dmSchedulerSeat.getAreaLevel());
            if (dmprice!=null) {
                price+=dmprice.getPrice();
            }

            //将vo数据中的联系人进行分割并保存在一个数组中
            linkuserId = vo.getLinkIds().split(",");

            //查询当前下单人是否拥有当前联系人id,不存在则返回错误信息
            LinkUser linkUser = userFeign.user(Long.parseLong(linkuserId[i]));
            if (linkUser==null) {
                return ResponseUtil.returnFail(ErrConstant.ErrCodeConstant.NO_CODE_CONTACT,ErrConstant.ErrMsgConstant.NO_MSG_CONTACT);
            }
            //存在则循环新增订单联系人（dm-order-link-user）
            orderLinkUser orderLinkUser = new orderLinkUser();
            orderLinkUser.setOrderId(Long.parseLong(id));
            orderLinkUser.setLinkUserId(Long.parseLong(linkuserId[i]));
            orderLinkUser.setLinkUserName(linkUser.getName());
            orderLinkUser.setX(x);
            orderLinkUser.setY(y);
            orderLinkUser.setPrice(dmprice.getPrice());
            //分布式事务
            try {
                baseMapper.insert(orderLinkUser);
                //出现错误时就会被catch捕获，发送rabbitMQ中
                //int o= 5/0;
            }catch (Exception e){
                rabbitTemplate.convertAndSend("dm_ex_rollback","linkuser",id);
            }


            //修改座位的状态，用户id和订单编号
            DmSchedulerSeat schedulerSeat = new DmSchedulerSeat();
            schedulerSeat.setOrderNo(id);
            schedulerSeat.setUserId(Long.parseLong(linkuserId[i]));
            schedulerSeat.setStatus(3L);
            schedulerSeat.setX(x);
            schedulerSeat.setY(y);
            schedulerSeat.setScheduleId(schedulerId.longValue());

            //分布式事务
            try {
                schedulerFeign.updateschedulerseat(schedulerSeat);
            }catch (Exception e){
                rabbitTemplate.convertAndSend("dm_ex_rollback","linkuser",id);
                rabbitTemplate.convertAndSend("dm_ex_rollback","seat",id);
            }

        }

        //判断是否需要保险，如果需要保险则在总金额上加20
        if (vo.getIsNeedInsurance()==1) {
            price+=20;
        }


        //三个数据修改
        //新增订单
        order.setOrderNo(id);
        order.setUserId(Long.parseLong(userId));
        order.setSchedulerId(schedulerId.longValue());
        order.setItemId(vo.getItemId());
        order.setItemName(item.getItemName());
        order.setTotalAmount(price);
        order.setIsNeedInsurance(vo.getIsNeedInsurance().longValue());
        order.setPayType("1");
        order.setTotalCount((long) seats.length);
        order.setSourceType(0L);
        order.setOrderType(0L);

        order.setCreatedTime(LocalDateTime.now());
        if (vo.getIsNeedInsurance()==1) {
            order.setInsuranceAmount(20D);
        }
        //是否需要发票
        if (vo.getInvoiceType()==1) {
            order.setIsNeedInvoice(1L);
            //是否是公司发票
            if(vo.getInvoiceType() == 1){
                order.setInvoiceType(1L);
                order.setInvoiceHead(vo.getInvoiceHead());
                order.setInvoiceNo(vo.getInvoiceNo());
            }else{
                order.setInvoiceType(0L);
            }
        }
        //分布式事务
        try {
            queryorderlistService.addorder(order);
        }catch (Exception e){
            rabbitTemplate.convertAndSend("dm_ex_rollback","linkuser",order.getOrderNo());
            rabbitTemplate.convertAndSend("dm_ex_rollback","seat",order.getOrderNo());
            rabbitTemplate.convertAndSend("dm_ex_rollback","order",order.getOrderNo());
        }


        //用户下单完毕后需要解锁剧院
        redisTemplate.delete("lock");

        //将订单发送到rabbitMQ中,进行延时支付
        rabbitTemplate.convertAndSend("dm_order_exchange","dm.order",order.getOrderNo(),
                message -> {
                    message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT); //持久化
                    message.getMessageProperties().setExpiration("60000");//过期时间
                    return message;
                });

        //最终返回客户端的是订单编号
        Map<String,String> map = new HashMap<>();
        map.put("orderNo",id);

        return ResponseUtil.returnSuccess(map);
    }

    @Override
    public Integer deleteorderLinkUser(String orderNo) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("orderId",orderNo);

        return baseMapper.delete(queryWrapper);
    }
}
